

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="Blue~u~u~u">
  <meta name="author" content="Blue~u~u~u">
  <meta name="keywords" content="">
  <meta name="description" content="一、用户身份认证1、单一服务器模式 一般过程如下：  用户向服务器发送用户名和密码。 验证服务器后，相关数据（如用户名，用户角色等）将保存在当前会话（session）中。 服务器向用户返回session_id，session信息都会写入到用户的Cookie。 用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。 服务器收到session_id并对比之前保存的数据，确认用户">
<meta property="og:type" content="article">
<meta property="og:title" content="单点登录学习笔记">
<meta property="og:url" content="http://www.slx.blue/2022/02/11/%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95/index.html">
<meta property="og:site_name" content="Blue~u~u~u~u">
<meta property="og:description" content="一、用户身份认证1、单一服务器模式 一般过程如下：  用户向服务器发送用户名和密码。 验证服务器后，相关数据（如用户名，用户角色等）将保存在当前会话（session）中。 服务器向用户返回session_id，session信息都会写入到用户的Cookie。 用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。 服务器收到session_id并对比之前保存的数据，确认用户">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image01.jpg">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image02.jpg">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image03.jpg">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image04.jpg">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image05.jpg">
<meta property="article:published_time" content="2022-02-11T13:31:40.000Z">
<meta property="article:modified_time" content="2022-02-11T13:32:34.095Z">
<meta property="article:author" content="Blue~u~u~u">
<meta property="article:tag" content="JWT">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image01.jpg">
  
  <title>单点登录学习笔记 - Blue~u~u~u~u</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"www.slx.blue","root":"/","version":"1.8.12","typing":{"enable":true,"typeSpeed":180,"cursorChar":"_","loop":true},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname"}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"></head>

<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css"/>
<script src="/live2d-widget/autoload.js"></script>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Blue~u~u</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/images/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="单点登录学习笔记">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2022-02-11 21:31" pubdate>
        2022年2月11日 晚上
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      5.9k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      18 分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">单点登录学习笔记</h1>
            
              <p class="note note-info">
                
                  本文最后更新于：4 个月前
                
              </p>
            
            <div class="markdown-body">
              <h1 id="一、用户身份认证"><a href="#一、用户身份认证" class="headerlink" title="一、用户身份认证"></a><strong>一、用户身份认证</strong></h1><h2 id="1、单一服务器模式"><a href="#1、单一服务器模式" class="headerlink" title="1、单一服务器模式"></a>1、单一服务器模式</h2><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image01.jpg" srcset="/img/loading.gif" lazyload alt="img"></p>
<p><strong>一般过程如下：</strong></p>
<ol>
<li>用户向服务器发送用户名和密码。</li>
<li>验证服务器后，相关数据（如用户名，用户角色等）将保存在当前会话（session）中。</li>
<li>服务器向用户返回session_id，session信息都会写入到用户的Cookie。</li>
<li>用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。</li>
<li>服务器收到session_id并对比之前保存的数据，确认用户的身份。</li>
</ol>
<p><strong>缺点：</strong></p>
<ul>
<li>单点性能压力，无法扩展。</li>
<li>分布式架构中，需要session共享方案，session共享方案存在性能瓶颈。</li>
</ul>
<p><strong>session共享方案：</strong></p>
<p>session广播：性能瓶颈，不推荐</p>
<p>redis代替session：推荐，性能高</p>
<h2 id="2、SSO（Single-Sign-On）模式"><a href="#2、SSO（Single-Sign-On）模式" class="headerlink" title="2、SSO（Single Sign On）模式"></a>2、SSO（Single Sign On）模式</h2><p>CAS单点登录、OAuth2</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image02.jpg" srcset="/img/loading.gif" lazyload alt="img"></p>
<p>分布式，SSO(single sign on)模式：单点登录英文全称Single Sign On，简称就是SSO。它的解释是：在多个应用系统中，只需要登录一次，就可以访问其他相互信任的应用系统。</p>
<ul>
<li>如图所示，图中有3个系统，分别是业务A、业务B、和SSO。</li>
<li>业务A、业务B没有登录模块。</li>
<li>而SSO只有登录模块，没有其他的业务模块。</li>
</ul>
<p><strong>一般过程如下：</strong></p>
<ol>
<li>当业务A、业务B需要登录时，将跳到SSO系统。</li>
<li>SSO从用户信息数据库中获取用户信息并校验用户信息，SSO系统完成登录。</li>
<li>然后将用户信息存入缓存（例如redis）。</li>
<li>当用户访问业务A或业务B，需要判断用户是否登录时，将跳转到SSO系统中进行用户身份验证，SSO判断缓存中是否存在用户身份信息。</li>
<li>这样，只要其中一个系统完成登录，其他的应用系统也就随之登录了。这就是单点登录（SSO）的定义。</li>
</ol>
<p><strong>优点 ：</strong>  </p>
<p>用户身份信息独立管理，更好的分布式管理。可以自己扩展安全策略</p>
<p><strong>缺点：</strong></p>
<p>认证服务器访问压力较大。</p>
<h2 id="3、Token模式"><a href="#3、Token模式" class="headerlink" title="3、Token模式"></a>3、Token模式</h2><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image03.jpg" srcset="/img/loading.gif" lazyload alt="img"></p>
<p><strong>优点：</strong></p>
<ul>
<li>无状态： token是无状态，session是有状态的</li>
<li>基于标准化：你的API可以采用标准化的 JSON Web Token (JWT)</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>占用带宽</li>
<li>无法在服务器端销毁</li>
</ul>
<p> 一、访问令牌的类型</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image04.jpg" srcset="/img/loading.gif" lazyload alt="img"></p>
<h1 id="二、JWT令牌"><a href="#二、JWT令牌" class="headerlink" title="二、JWT令牌"></a>二、JWT令牌</h1><h2 id="1、什么是JWT令牌"><a href="#1、什么是JWT令牌" class="headerlink" title="1、什么是JWT令牌"></a>1、什么是JWT令牌</h2><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm"><span class="hljs-keyword">JWT是JSON </span>Web Token的缩写，即<span class="hljs-keyword">JSON </span>Web令牌，是一种自包含令牌。 <br><span class="hljs-keyword">JWT的使用场景：</span><br><span class="hljs-keyword"></span>一种情况是webapi，类似之前的阿里云播放凭证的功能另一种情况是多web服务器下实现无状态分布式身份验证<span class="hljs-keyword">JWT官网有一张图描述了JWT的认证过程JWT的作用：JWT </span>最重要的作用就是对 token信息的防伪作用<span class="hljs-keyword">JWT的原理：一个JWT由三个部分组成：JWT头、有效载荷、签名哈希最后由这三者组合进行base64编码得到JWT</span><br></code></pre></td></tr></table></figure>

<h2 id="2、JWT令牌的组成"><a href="#2、JWT令牌的组成" class="headerlink" title="2、JWT令牌的组成"></a>2、JWT令牌的组成</h2><p>典型的，一个JWT看起来如下图：</p>
<p><a target="_blank" rel="noopener" href="https://jwt.io/">https://jwt.io/</a></p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/jwt/image/image05.jpg" srcset="/img/loading.gif" lazyload alt="img"></p>
<p>该对象为一个很长的字符串，字符之间通过”.”分隔符分为三个子串。</p>
<p>每一个子串表示了一个功能块，总共有以下三个部分：JWT头、有效载荷和签名</p>
<p><em><strong>*J*<em>WT</em></strong></em>头**</p>
<p>JWT头部分是一个描述JWT元数据的JSON对象，通常如下所示。</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs json">&#123;<br>  <span class="hljs-attr">&quot;alg&quot;</span>: <span class="hljs-string">&quot;HS256&quot;</span>,<br>  <span class="hljs-attr">&quot;typ&quot;</span>: <span class="hljs-string">&quot;JWT&quot;</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>在上面的代码中，alg属性表示签名使用的算法，默认为HMAC SHA256（写为HS256）；typ属性表示令牌的类型，JWT令牌统一写为JWT。最后，使用Base64 URL算法将上述JSON对象转换为字符串保存。</p>
<p><strong>有效载荷</strong></p>
<p>有效载荷部分，是JWT的主体内容部分，也是一个JSON对象，包含需要传递的数据。 JWT指定七个默认字段供选择。</p>
<figure class="highlight avrasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs avrasm"><span class="hljs-symbol">sub:</span> 主题<br><span class="hljs-symbol">iss:</span> jwt签发者<br><span class="hljs-symbol">aud:</span> 接收jwt的一方<br><span class="hljs-symbol">iat:</span> jwt的签发时间<br><span class="hljs-symbol">exp:</span> jwt的过期时间，这个过期时间必须要大于签发时间<br><span class="hljs-symbol">nbf:</span> 定义在什么时间之前，该jwt都是不可用的.<br><span class="hljs-symbol">jti:</span> jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击。<br></code></pre></td></tr></table></figure>

<p>除以上默认字段外，我们还可以自定义私有字段，如下例：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs json">&#123;<br>  <span class="hljs-attr">&quot;name&quot;</span>: <span class="hljs-string">&quot;Helen&quot;</span>,<br>  <span class="hljs-attr">&quot;admin&quot;</span>: <span class="hljs-literal">true</span>,<br>  <span class="hljs-attr">&quot;avatar&quot;</span>: <span class="hljs-string">&quot;helen.jpg&quot;</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>请注意，默认情况下JWT是未加密的，任何人都可以解读其内容，因此不要构建隐私信息字段，存放保密信息，以防止信息泄露。</p>
<p>JSON对象也使用Base64 URL算法转换为字符串保存。</p>
<p><strong>签名哈希</strong></p>
<p>签名哈希部分是对上面两部分数据签名，通过指定的算法生成哈希，以确保数据不会被篡改。</p>
<p>首先，需要指定一个密码（secret）。该密码仅仅为保存在服务器中，并且不能向用户公开。然后，使用标头中指定的签名算法（默认情况下为HMAC SHA256）根据以下公式生成签名。</p>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs reasonml"><span class="hljs-constructor">HMACSHA256(<span class="hljs-params">base64UrlEncode</span>(<span class="hljs-params">header</span>)</span> + <span class="hljs-string">&quot;.&quot;</span> + base64<span class="hljs-constructor">UrlEncode(<span class="hljs-params">claims</span>)</span>, secret)    ==&gt;   签名hash<br></code></pre></td></tr></table></figure>

<p>在计算出签名哈希后，JWT头，有效载荷和签名哈希的三个部分组合成一个字符串，每个部分用”.”分隔，就构成整个JWT对象。</p>
<p><strong>Base64URL算法</strong></p>
<p>如前所述，JWT头和有效载荷序列化的算法都用到了Base64URL。该算法和常见Base64算法类似，稍有差别。</p>
<p>作为令牌的JWT可以放在URL中（例如api.example/?token=xxx）。 Base64中用的三个字符是”+”，”/“和”=”，由于在URL中有特殊含义，因此Base64URL中对他们做了替换：”=”去掉，”+”用”-“替换，”/“用”_”替换，这就是Base64URL算法。</p>
<p><strong>注意：</strong>base64编码，并不是加密，只是把明文信息变成了不可见的字符串。但是其实只要用一些工具就可以把base64编码解成明文，所以不要在JWT中放入涉及私密的信息。</p>
<h2 id="3、JWT的用法"><a href="#3、JWT的用法" class="headerlink" title="3、JWT的用法"></a>3、JWT的用法</h2><p>客户端接收服务器返回的JWT，将其存储在Cookie或localStorage中。</p>
<p>此后，客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中，就可以自动发送，但是不会跨域，因此一般是将它放入HTTP请求的Header Authorization字段中。</p>
<p>当跨域时，也可以将JWT放置于POST请求的数据主体中。</p>
<h1 id="三、JWT问题和趋势"><a href="#三、JWT问题和趋势" class="headerlink" title="三、JWT问题和趋势"></a>三、JWT问题和趋势</h1><p>1、JWT默认不加密，但可以加密。生成原始令牌后，可以使用该令牌再次对其进行加密。</p>
<p>2、当JWT未加密时，一些私密数据无法通过JWT传输。</p>
<p>3、JWT不仅可用于认证，还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数。</p>
<p>4、JWT的最大缺点是服务器不保存会话状态，所以在使用期间不可能取消令牌或更改令牌的权限。也就是说，一旦JWT签发，在有效期内将会一直有效。</p>
<p>5、JWT本身包含认证信息，因此一旦信息泄露，任何人都可以获得令牌的所有权限。为了减少盗用，JWT的有效期不宜设置太长。对于某些重要操作，用户在使用时应该每次都进行身份验证。</p>
<p>6、为了减少盗用和窃取，JWT不建议使用HTTP协议来传输代码，而是使用加密的HTTPS协议进行传输。</p>
<p>7、那么cas认证中心式的单点登录，和jwt无状态的单点登录区别是什么，这两种分别适用什么样的系统？</p>
<ul>
<li>Jwt算法登录消耗的是cpu资源，在高并发下，考验的式服务器的cpu的算力</li>
<li>Cas认证中心式的单点登录消耗的是内存资源，在高并发下，考验的是内存的存储能力</li>
</ul>
<h1 id="四、JWT案例"><a href="#四、JWT案例" class="headerlink" title="四、JWT案例"></a>四、JWT案例</h1><h2 id="1、项目"><a href="#1、项目" class="headerlink" title="1、项目"></a>1、项目</h2><p>项目类型：Maven</p>
<p>groupId：com.atguigu</p>
<p>artifactId：jwt</p>
<h2 id="2、基本依赖"><a href="#2、基本依赖" class="headerlink" title="2、基本依赖"></a>2、基本依赖</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span><br>    <span class="hljs-comment">&lt;!-- JWT --&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.jsonwebtoken<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jjwt<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.7.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-comment">&lt;!--junit--&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>junit<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>junit<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.12<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br>    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h1 id="二、测试JWT"><a href="#二、测试JWT" class="headerlink" title="二、测试JWT"></a>二、测试JWT</h1><h2 id><a href="#" class="headerlink" title></a></h2><h2 id="1、生成token"><a href="#1、生成token" class="headerlink" title="1、生成token"></a>1、生成token</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.atguigu.jwt;<br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JwtTests</span> </span>&#123;<br>    <span class="hljs-comment">//过期时间，毫秒，24小时</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">long</span> tokenExpiration = <span class="hljs-number">24</span>*<span class="hljs-number">60</span>*<span class="hljs-number">60</span>*<span class="hljs-number">1000</span>;<br>    <span class="hljs-comment">//秘钥</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String tokenSignKey = <span class="hljs-string">&quot;atguigu123&quot;</span>;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testCreateToken</span><span class="hljs-params">()</span></span>&#123;<br>        String token = Jwts.builder()<br>                .setHeaderParam(<span class="hljs-string">&quot;typ&quot;</span>, <span class="hljs-string">&quot;JWT&quot;</span>) <span class="hljs-comment">//令牌类型</span><br>                .setHeaderParam(<span class="hljs-string">&quot;alg&quot;</span>, <span class="hljs-string">&quot;HS256&quot;</span>) <span class="hljs-comment">//签名算法</span><br>                .setSubject(<span class="hljs-string">&quot;guli-user&quot;</span>) <span class="hljs-comment">//令牌主题</span><br>                .setIssuer(<span class="hljs-string">&quot;atguigu&quot;</span>)<span class="hljs-comment">//签发者</span><br>                .setAudience(<span class="hljs-string">&quot;atguigu&quot;</span>)<span class="hljs-comment">//接收者</span><br>                .setIssuedAt(<span class="hljs-keyword">new</span> Date())<span class="hljs-comment">//签发时间</span><br>                .setExpiration(<span class="hljs-keyword">new</span> Date(System.currentTimeMillis() + tokenExpiration)) <span class="hljs-comment">//过期时间</span><br>                .setNotBefore(<span class="hljs-keyword">new</span> Date(System.currentTimeMillis() + <span class="hljs-number">20</span>*<span class="hljs-number">1000</span>)) <span class="hljs-comment">//20秒后可用</span><br>                .setId(UUID.randomUUID().toString())<br>                .claim(<span class="hljs-string">&quot;nickname&quot;</span>, <span class="hljs-string">&quot;Helen&quot;</span>)<br>                .claim(<span class="hljs-string">&quot;avatar&quot;</span>, <span class="hljs-string">&quot;1.jpg&quot;</span>)<br>                .signWith(SignatureAlgorithm.HS256, tokenSignKey)<span class="hljs-comment">//签名哈希</span><br>                .compact(); <span class="hljs-comment">//转换成字符串</span><br>        System.out.println(token);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="2、解析token"><a href="#2、解析token" class="headerlink" title="2、解析token"></a>2、解析token</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testGetUserInfo</span><span class="hljs-params">()</span></span>&#123;<br>    String token = <span class="hljs-string">&quot;jwt字符串&quot;</span>;<br>    Jws&lt;Claims&gt; claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);<br>    Claims claims = claimsJws.getBody();<br>    String subject = claims.getSubject();<br>    String issuer = claims.getIssuer();<br>    String audience = claims.getAudience();<br>    Date issuedAt = claims.getIssuedAt();<br>    Date expiration = claims.getExpiration();<br>    Date notBefore = claims.getNotBefore();<br>    String id = claims.getId();<br>    System.out.println(subject);<br>    System.out.println(issuer);<br>    System.out.println(audience);<br>    System.out.println(issuedAt);<br>    System.out.println(expiration);<br>    System.out.println(notBefore);<br>    System.out.println(id);;<br>    String nickname = (String)claims.get(<span class="hljs-string">&quot;nickname&quot;</span>);<br>    String avatar = (String)claims.get(<span class="hljs-string">&quot;avatar&quot;</span>);<br>    System.out.println(nickname);<br>    System.out.println(avatar);<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="3、加密解密优化"><a href="#3、加密解密优化" class="headerlink" title="3、加密解密优化"></a>3、加密解密优化</h2><p>JWT的最大缺点是服务器不保存会话状态，所以在使用期间不可能取消令牌或更改令牌的权限，所以若token丢失情况，会导致账号信息被盗用。因此我们可以采取加盐的方式，比如加密的tokenSignKey拼接IP地址，这样另一台电脑即使盗取了token也无法登陆。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"> <span class="hljs-comment">//签名信息</span><br>        String ip = <span class="hljs-string">&quot;127.0.0.1&quot;</span>;  <span class="hljs-comment">//此处替换成获取ip的方法</span><br><span class="hljs-comment">//        builder.signWith(SignatureAlgorithm.HS256, MD5.encrypt(serviceKey+ip));</span><br>        builder.signWith(SignatureAlgorithm.HS256, tokenSignKey+ip);<br></code></pre></td></tr></table></figure>

<p>但是由于算法的特性，ip相似的情况下</p>
<p> 还是有可能通过解密的 比如ip为127.0.0.9 ，依然被解密成功。（不信自行测试）</p>
<p>因此我们可以采用继续加密的方式，把算法的误差再次减小 比如把签名哈希再次用MD5进行加密解密。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">builder.signWith(SignatureAlgorithm.HS256, MD5.encrypt(tokenSignKey+ip));<br></code></pre></td></tr></table></figure>

<p>这样即使token丢失也不需要太担心了，但是不建议多重加密，毕竟这样消耗的是CPU的资源。</p>
<p>Jwt算法登录消耗的是cpu资源，在高并发下，考验的式服务器的cpu的算力。所以 JWT登录适用于中小型系统</p>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/%E7%99%BB%E5%BD%95%E9%AA%8C%E8%AF%81/">登录验证</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/JWT/">JWT</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客目前大部分文章都是参考尚硅谷或者马士兵教育的学习资料！<a href="http://www.atguigu.com/" rel="nofollow noopener"官网地址！</a> 
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/02/11/aliOss/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">阿里云存储OSS学习笔记及入门案例</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/01/23/docker-linux/">
                        <span class="hidden-mobile">linux安装Docker及常见的坑</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments" lazyload>
                
                  
                
                

              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">

  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
	<!--《添加网站运行时间 -->
<br/>

<span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
<script>
var now = new Date(); 

function createtime() {
    //此处修改你的建站时间或者网站上线时间
    var grt = new Date('11/02/2021 21:39:00');
    now.setTime(now.getTime() + 250);
    days = (now - grt) / 1000 / 60 / 60 / 24;

    dnum = Math.floor(days);
    hours = (now - grt) / 1000 / 60 / 60 - (24 * dnum);
    hnum = Math.floor(hours);
    if (String(hnum).length == 1) {
        hnum = "0" + hnum;
    }
    minutes = (now - grt) / 1000 / 60 - (24 * 60 * dnum) - (60 * hnum);
    mnum = Math.floor(minutes);
    if (String(mnum).length == 1) {
        mnum = "0" + mnum;
    }
    seconds = (now - grt) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
    snum = Math.round(seconds);
    if (String(snum).length == 1) {
        snum = "0" + snum;
    }
    document.getElementById("timeDate").innerHTML = " 本站已各种夹缝中安全运行 " + dnum + " 天 ";
    document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
}
setInterval("createtime()", 250);
</script>

<!-- 添加网站运行时间》-->
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
